package com.tomato.dynamic.threadpool.core.support;

import com.tomato.dynamic.threadpool.common.enums.QueueTypeEnum;
import com.tomato.dynamic.threadpool.core.thread.DynamicThreadPoolExecutor;

import java.math.BigDecimal;
import java.util.concurrent.*;

/**
 * 线程池创建 builder
 *
 * @author lizhifu
 * @date 2022/3/4
 */
@Deprecated
public class ThreadPoolBuilder {
    /**
     * 是否动态调整线程池大小
     */
    private boolean dynamic = true;
    /**
     * 线程名称前缀
     */
    private String threadNamePrefix;
    /**
     * 允许核心线程超时
     */
    private Boolean allowCoreThreadTimeOut = false;
    /**
     * 当线程池中线程数量大于corePoolSize（核心线程数量）或设置了allowCoreThreadTimeOut（是否允许空闲核心线程超时）时，
     * 线程会根据keepAliveTime的值进行活性检查，一旦超时便销毁线程。
     */
    private long keepAliveTime = 30;
    /**
     * 时间单位
     */
    private TimeUnit timeUnit = TimeUnit.SECONDS;
    /**
     * 线程池名称
     */
    private String threadPoolName = "TomatoThreadPool";
    /**
     * 核心线程数量 = CPU 核数 / (1 - 阻塞系数 0.8)
     * 线程池的基本大小，即在没有任务需要执行的时候线程池的大小，并且只有在工作队列满了的情况下才会创建超出这个数量的线程
     */
    private int corePoolSize = calculateCoreNum();

    /**
     * 最大线程数量 = 核心线程数量 +
     * 线程池中允许的最大线程数，线程池中的当前线程数目不会超过该值。
     * 如果队列中任务已满，并且当前线程个数小于 maxPoolSize ，那么会创建新的线程来执行任务
     */
    private int maxPoolSize = corePoolSize + (corePoolSize >> 1);


    /** ================================队列相关================================ start ***/
    /**
     * 队列默认最大容量
     */
    private static final int capacity = 512;
    /**
     * 阻塞队列
     */
    private BlockingQueue workQueue = new LinkedBlockingQueue(capacity);

    /**
     * 线程池任务满时拒绝任务策略
     * 默认：被拒绝任务的处理程序, 抛出异常
     */
    private RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.AbortPolicy();

    /** ================================队列相关 end ================================***/

    /**
     * 是否守护线程
     */
    private boolean isDaemon = false;
    /**
     * 不中断正在运行的任务并执行队列中的所有任务。
     */
    private boolean waitForTasksToCompleteOnShutdown = false;
    /**
     * awaitTerminationSeconds 等待时间
     */
    protected int awaitTerminationSeconds = 0;
    /**
     * 计算公式：CPU 核数 / (1 - 阻塞系数 0.8)
     *
     * @return 线程池核心线程数
     */
    private Integer calculateCoreNum() {
        // CPU 核数
        int cpuCoreNum = Runtime.getRuntime().availableProcessors();
        return new BigDecimal(cpuCoreNum).divide(new BigDecimal("0.2")).intValue();
    }

    private ThreadPoolBuilder() {}

    public static ThreadPoolBuilder newBuilder() {
        return new ThreadPoolBuilder();
    }

    public ThreadPoolBuilder threadFactory(String threadNamePrefix) {
        this.threadNamePrefix = threadNamePrefix;
        return this;
    }

    public ThreadPoolBuilder threadPoolName(String poolName) {
        this.threadPoolName = poolName;
        return this;
    }

    public ThreadPoolBuilder corePoolSize(int corePoolSize) {
        if (corePoolSize >= 0) {
            this.corePoolSize = corePoolSize;
        }
        return this;
    }

    public ThreadPoolBuilder maxPoolSize(int maxPoolSize) {
        if (maxPoolSize > 0) {
            this.maxPoolSize = maxPoolSize;
        }
        return this;
    }

    public ThreadPoolBuilder keepAliveTime(long keepAliveTime) {
        if (keepAliveTime > 0) {
            this.keepAliveTime = keepAliveTime;
        }
        return this;
    }

    public ThreadPoolBuilder timeUnit(TimeUnit timeUnit) {
        if (timeUnit != null) {
            this.timeUnit = timeUnit;
        }
        return this;
    }

    public ThreadPoolBuilder workQueue(QueueTypeEnum queueType, int capacity) {
        this.workQueue =  QueueTypeEnum.buildBlockingQueue(queueType.getName(),capacity);
        return this;
    }

    public ThreadPoolBuilder rejected(RejectedExecutionHandler rejectedExecutionHandler) {
        this.rejectedExecutionHandler = rejectedExecutionHandler;
        return this;
    }

    public ThreadPoolExecutor build() {
        if (dynamic) {
            return buildDynamicExecutor(this);
        } else {
            return buildCommonExecutor(this);
        }
    }

    private ThreadPoolExecutor buildDynamicExecutor(ThreadPoolBuilder builder) {
        ThreadFactory threadFactory = ThreadFactoryBuilder.newBuilder()
                .prefix(threadNamePrefix)
                .daemon(dynamic)
                .build();
        DynamicThreadPoolExecutor dynamicThreadPoolExecutor = new DynamicThreadPoolExecutor(
                builder.corePoolSize,
                builder.maxPoolSize,
                builder.keepAliveTime,
                builder.timeUnit,
                builder.workQueue,
                threadFactory,
                builder.rejectedExecutionHandler);
        dynamicThreadPoolExecutor.setThreadPoolName(builder.threadPoolName);
        dynamicThreadPoolExecutor.allowCoreThreadTimeOut(builder.allowCoreThreadTimeOut);
        dynamicThreadPoolExecutor.setWaitForTasksToCompleteOnShutdown(builder.waitForTasksToCompleteOnShutdown);
        dynamicThreadPoolExecutor.setAwaitTerminationSeconds(builder.awaitTerminationSeconds);
        return dynamicThreadPoolExecutor;
    }

    private ThreadPoolExecutor buildCommonExecutor(ThreadPoolBuilder builder) {
        ThreadFactory threadFactory = ThreadFactoryBuilder.newBuilder()
                .prefix(threadNamePrefix)
                .daemon(dynamic)
                .build();
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                builder.corePoolSize,
                builder.maxPoolSize,
                builder.keepAliveTime,
                builder.timeUnit,
                builder.workQueue,
                threadFactory,
                builder.rejectedExecutionHandler
        );
        executor.allowCoreThreadTimeOut(builder.allowCoreThreadTimeOut);
        return executor;
    }
}
